#pragma once

#include "Utils.hpp"
#include <iostream>
#include <string>

namespace MonsterFactory {

  // monster interface
  class IMonster {
  protected:
    unsigned int level;
    std::string name;
  public:
    std::string GetName() {return name;};
    unsigned int GetLevel() {return level;}

    virtual bool PerformTask() = 0;
    virtual std::string OpeningWords() = 0;
  };

  // interfaces are still abstract classes
  // animal monster interface
  class IAnimalMonster : public IMonster {
    bool PerformTask();
  };
  // plant monster interface
  class IPlantMonster : public IMonster {
    bool PerformTask();    
  };
  // elite monster interface
  class IEliteMonster : public IMonster {
    bool PerformTask();    
  };

  class BossMonster : public IEliteMonster {
  public:
    BossMonster(int level);
    ~BossMonster() {}

    std::string OpeningWords();

  private:
    BossMonster(){}
    BossMonster& operator=(const BossMonster&) {};
    BossMonster(const BossMonster&) {};
  };
  
  class PigMonster : public IAnimalMonster {
  public:
    PigMonster(int level);
    ~PigMonster() {}

    std::string OpeningWords();    
  private:
    PigMonster(){}
    PigMonster& operator=(const PigMonster&) {};
    PigMonster(const PigMonster&) {};
  };

  class HorseMonster : public IAnimalMonster {
  public:
    HorseMonster(int level);
    ~HorseMonster() {}

    std::string OpeningWords();
  private:
    HorseMonster(){}
    HorseMonster& operator=(const HorseMonster&) {};
    HorseMonster(const HorseMonster&) {};
  };

  class TreeMonster : public IPlantMonster {
  public:
    TreeMonster(int level);
    ~TreeMonster() {}

    std::string OpeningWords();    
  private:
    TreeMonster(){}
    TreeMonster& operator=(const TreeMonster&) {};
    TreeMonster(const TreeMonster&) {};
  };
  
  class FlowerMonster : public IPlantMonster {
  public:
    FlowerMonster(int level);
    ~FlowerMonster() {}

    std::string OpeningWords();    
  private:
    FlowerMonster(){}
    FlowerMonster& operator=(const FlowerMonster&) {};
    FlowerMonster(const FlowerMonster&) {};
  };
}
